package com.stu.module.config;

import com.stu.module.SimpleJobListener;
import com.stu.module.bean.Access;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.JpaPagingItemReader;
import org.springframework.batch.item.database.orm.JpaNativeQueryProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;

/**
 * @projectName: learn_used_code
 * @packageName: com.stu.module.config
 * @className: com.stu.module.config-> BatchTaskConfigration
 * @createDate: 2021-10-22 16:23
 * @author: ZhangSheng
 * @version: 1.0
 * @description:
 */
@Configuration
@EnableBatchProcessing
public class BatchTaskConfigration {

    private static Logger logger = LoggerFactory.getLogger(BatchTaskConfigration.class);

    @Resource
    private JobBuilderFactory jobBuilderFactory;

    @Resource
    private StepBuilderFactory stepBuilderFactory;

    @Resource
    private EntityManagerFactory entityManagerFactory;

    @Resource
    private SimpleJobListener simpleJobListener;





    /**
     * 一个简单基础的Job通常由一个或者多个Step组成
     */
    @Bean
    public Job dataHandleJob() {
        return jobBuilderFactory.get("dataHandleJob").
                incrementer(new RunIdIncrementer()).
//      start是JOB执行的第一个step
                start(handleDataStep()).
//                next(xxxStep()).
//                next(xxxStep()).
//                ...
//      设置了一个简单JobListener
        listener(simpleJobListener).
                build();
    }

    /**
     * 一个简单基础的Step主要分为三个部分
     * ItemReader : 用于读取数据
     * ItemProcessor : 用于处理数据
     * ItemWriter : 用于写数据
     */
    @Bean
    public Step handleDataStep() {
        return stepBuilderFactory.get("getDataStep").
                // <输入,输出> 。chunk通俗的讲类似于SQL的commit; 这里表示处理(processor)100条后写入(writer)一次。
                <Access, Access>chunk(100).
                faultTolerant().retryLimit(3)
                .retry(Exception.class)
                .skipLimit(100)
                 //异常跳过
                .skip(Exception.class)
                //指定ItemReader
                .reader(getDataReader())
                //指定ItemProcessor
                .processor(getDataProcessor())
                //指定ItemWriter
                .writer(getDataWriter())
                .build();
    }

    @Bean
    public ItemReader<? extends Access> getDataReader() {
        logger.info("====读取数据====");
        //读取数据,这里可以用JPA,JDBC,JMS 等方式 读入数据
        JpaPagingItemReader<Access> reader = new JpaPagingItemReader<>();
        //这里选择JPA方式读数据 一个简单的 native SQL
        String sqlQuery = "SELECT * FROM access";
        try {
            JpaNativeQueryProvider<Access> queryProvider = new JpaNativeQueryProvider<>();
            queryProvider.setSqlQuery(sqlQuery);
            queryProvider.setEntityClass(Access.class);
            queryProvider.afterPropertiesSet();
            reader.setEntityManagerFactory(entityManagerFactory);
            reader.setPageSize(3);
            reader.setQueryProvider(queryProvider);
            reader.afterPropertiesSet();
            //所有ItemReader和ItemWriter实现都会在ExecutionContext提交之前将其当前状态存储在其中,
            // 如果不希望这样做,可以设置setSaveState(false)
            reader.setSaveState(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return reader;
    }

    @Bean
    public ItemProcessor<Access, Access> getDataProcessor() {
        return new ItemProcessor<Access, Access>() {
            @Override
            public Access process(Access access) throws Exception {
                //模拟  假装处理数据,这里处理就是打印一下
                int num = 1/0;
                logger.info("模拟处理数据 : " + access.toString());
                return access;
            }
        };
    }

    @Bean
    public ItemWriter<Access> getDataWriter() {
        return list -> {
            for (Access access : list) {
                //模拟 假装写数据 ,这里写真正写入数据的逻辑
                logger.info("模拟写入数据 : " + access.toString());
            }
        };
    }


}
